local game2048 = class("Game2048") {
    x = 0;
    y = 0;
    label = "2048";
    checkerboard = {};
    score = 0;
}

function game2048:__init__(x,y,label)
    self.x = x or 0;
    self.y = y or 0;
    self:restart();
    self.label = label or "2048";
end

function game2048:restart()
    love.math.setRandomSeed(233)
    for i = 1,Game.CHECKERBOARD_NUMBER do
        self.checkerboard[i] = 0;
    end
    self.score = 0;
end

function game2048:getGrid(x,y)
    local i = (y - 1) * Game.CHECKERBOARD_WIDTH + x;
    if(i <=0 or i > Game.CHECKERBOARD_NUMBER) then return nil end;
    return self.checkerboard[i];
end

function game2048:setGrid(x,y,v)
    local i = (y - 1) * Game.CHECKERBOARD_WIDTH + x;
    if(i <=0 or i > Game.CHECKERBOARD_NUMBER) then return nil end;
    self.checkerboard[i] = v;
end

function game2048:_move_(x,y,dx,dy)
    local nx,ny = x + dx,y + dy;
    local old = self:getGrid(x,y);
    local next = self:getGrid(nx,ny);
    local s = false;
    while 
        x >= 1 and x <= Game.CHECKERBOARD_WIDTH and
        y >= 1 and y <= Game.CHECKERBOARD_HEIGHT and
        nx >= 1 and nx <= Game.CHECKERBOARD_WIDTH and
        ny >= 1 and ny <= Game.CHECKERBOARD_HEIGHT 
    do
        old = self:getGrid(x,y);
        next = self:getGrid(nx,ny);
        if(next == 0) then
            self:setGrid(nx,ny,old)
            self:setGrid(x,y,0)
        elseif old == next then
            if(s == false) then
                s = true;
                self.score = self.score + (old + next)
                self:setGrid(nx,ny,old + next)
                self:setGrid(x,y,0)
            end
        end
        
        x = nx;
        y = ny;
        nx = nx + dx;
        ny = ny + dy;
    end
end

function game2048:_moveUp_()
    local w = Game.CHECKERBOARD_WIDTH;
    local h = Game.CHECKERBOARD_HEIGHT;
    for x = 1, w do
        for y = 1, h do
            self:_move_(x,y,0,-1)
        end
    end
    self:_next_();
end

function game2048:_moveDown_()
    local w = Game.CHECKERBOARD_WIDTH;
    local h = Game.CHECKERBOARD_HEIGHT;
    for x = 1, w do
        for y = h, 1,-1 do
            self:_move_(x,y,0,1)
        end
    end
    self:_next_();
end

function game2048:_moveLeft_()
    local w = Game.CHECKERBOARD_WIDTH;
    local h = Game.CHECKERBOARD_HEIGHT;
    for y = 1, h do
        for x = 1, w do
            self:_move_(x,y,-1,0)
        end
    end
    self:_next_();
end

function game2048:_moveRight_()
    local w = Game.CHECKERBOARD_WIDTH;
    local h = Game.CHECKERBOARD_HEIGHT;
    for y = 1, h do
        for x = w, 1,-1 do
           self:_move_(x,y,1,0)
        end
    end
    self:_next_();
end

function game2048:_findEmptyGrid_()
    local t = {}
    for i = 1,Game.CHECKERBOARD_NUMBER do
        if(self.checkerboard[i] == 0) then
            table.insert(t,i);
        end
    end
    return t;
end

function game2048:_next_()
    local eg = self:_findEmptyGrid_()
    local ri = eg[love.math.random(1,#eg)];
    local rn = 2;
    if love.math.random(0,100) > 60 then
        rn = 4;
    end
    if(ri ~= nil) then
        self.checkerboard[ri] = rn;
    end
end

function game2048:input(key)
    if key == "w" then
        self:_moveUp_();
    elseif key == 's' then
        self:_moveDown_();
    elseif key == 'a' then
        self:_moveLeft_();
    elseif key == 'd' then
        self:_moveRight_();
    end
end

function game2048:draw(ox,oy)
    ox = ox or self.x;
    oy = oy or self.y;

    local w = Game.CHECKERBOARD_WIDTH;
    local h = Game.CHECKERBOARD_HEIGHT;
    local s = Game.CHECKERBOARD_GRID_SIZE;
    local offset = (Game.CHECKERBOARD_GRID_SIZE - Game.CHECKERBOARD_TEXT_MAX_WIDTH) / 2;
    local offset2 = Game.CHECKERBOARD_GRID_OFFSET


    local box1_ox,box1_oy = ox,oy
    local box1_w = (s * Game.CHECKERBOARD_WIDTH) + (offset2 * (Game.CHECKERBOARD_WIDTH + 1))
    local box1_h = Game.FONT_HEIGHT + Game.CHECKERBOARD_GRID_OFFSET

    local box2_ox,box2_oy = ox,box1_oy + box1_h + Game.CHECKERBOARD_GRID_OFFSET;
    local box2_w = box1_w
    local box2_h = box2_w
    for y = 0, h - 1 do
        for x = 0, w - 1 do
            local v = self:getGrid(x + 1,y + 1)
            
            local ox2,oy2 = box2_ox + (x * (s + offset2) + offset2),box2_oy + (y * (s + offset2) + offset2)
            love.graphics.rectangle("line",ox2,oy2,s,s)

            local vstr = string.format("%6.6s",v);
            if(v == 0) then
                vstr = "";
            end

            love.graphics.print(vstr,ox2 + offset, oy2 + ((Game.CHECKERBOARD_GRID_SIZE / 2) - (Game.FONT_HEIGHT / 2)))
        end
    end
    love.graphics.rectangle("line",box1_ox,box1_oy,box1_w,box1_h)
    love.graphics.print(string.format("Score : %d",self.score),box1_ox + 10,box1_oy + box1_h / 2 - Game.FONT_HEIGHT / 2)
    local label_len = #self.label;
    local label_pix_len = label_len * Game.FONT_WIDTH;
    love.graphics.print(self.label,box1_ox + box1_w - label_pix_len - 5,box1_oy + box1_h / 2 - Game.FONT_HEIGHT / 2)
    love.graphics.rectangle("line",box2_ox,box2_oy,box2_w,box2_h)
end

return game2048